/*---------------------------------------------------------------------
 * File name: hal_gpio.h
 *
 * Copyright (c) <2020-2022>, <ChenLong>
 *
 * All rights reserved.
 *
 * Author: ChenLong
 * Email: worldlong@foxmail.com
 *--------------------------------------------------------------------*/
#pragma once
/*
*/
#include <cstdint>
#include <cstring>
/*
*/
#define HGPIO_PORT_BITS    4
#define HGPIO_PIN_BITS     16
#define HGPIO_MODE_BITS    5
#define HGPIO_TYPE_BITS    4
#define HGPIO_SPEED_BITS   2
#define HGPIO_STATUS_BITS  1
#define HGPIO_EXTI_BITS    3

/*
*/
#define HGPIO_PORT_POS    (0)
#define HGPIO_PIN_POS     (HGPIO_PORT_POS + HGPIO_PORT_BITS)
#define HGPIO_MODE_POS    (HGPIO_PIN_POS + HGPIO_PIN_BITS)
#define HGPIO_TYPE_POS    (HGPIO_MODE_POS + HGPIO_MODE_BITS)
#define HGPIO_SPEED_POS   (HGPIO_TYPE_POS + HGPIO_TYPE_BITS)
#define HGPIO_STATUS_POS  (HGPIO_SPEED_POS + HGPIO_SPEED_BITS)
#define HGPIO_EXTI_POS    (HGPIO_STATUS_POS + HGPIO_STATUS_BITS)
/*
*/
#define HGPIO_PORT_MASK   ((1<<HGPIO_PORT_BITS) - 1)
#define HGPIO_PIN_MASK    ((1<<HGPIO_PIN_BITS) - 1)
#define HGPIO_MODE_MASK   ((1<<HGPIO_MODE_BITS) - 1)
#define HGPIO_TYPE_MASK   ((1<<HGPIO_TYPE_BITS) - 1)
#define HGPIO_SPEED_MASK  ((1<<HGPIO_SPEED_BITS) - 1)
#define HGPIO_STATUS_MASK ((1<<HGPIO_STATUS_BITS) - 1)
#define HGPIO_EXTI_MASK   ((1<<HGPIO_EXTI_BITS) - 1)
#define HGPIO_CFG_MASK    (((uint64_t)HGPIO_PIN_MASK << HGPIO_PIN_POS) |\
                           ((uint64_t)HGPIO_MODE_MASK << HGPIO_MODE_POS) |\
                           ((uint64_t)HGPIO_TYPE_MASK << HGPIO_TYPE_POS) |\
                           ((uint64_t)HGPIO_SPEED_MASK << HGPIO_SPEED_POS) |\
                           ((uint64_t)HGPIO_STATUS_MASK << HGPIO_STATUS_POS))
/*
*/
#define HGPIO_A  (1 << HGPIO_PORT_POS)
#define HGPIO_B  (2 << HGPIO_PORT_POS)
#define HGPIO_C  (3 << HGPIO_PORT_POS)
#define HGPIO_D  (4 << HGPIO_PORT_POS)
#define HGPIO_E  (5 << HGPIO_PORT_POS)
#define HGPIO_F  (6 << HGPIO_PORT_POS)
#define HGPIO_G  (7 << HGPIO_PORT_POS)
#define HGPIO_H  (8 << HGPIO_PORT_POS)
#define HGPIO_I  (9 << HGPIO_PORT_POS)
#define HGPIO_J  (10 << HGPIO_PORT_POS)
#define HGPIO_K  (11 << HGPIO_PORT_POS)
#define HGPIO_PORT(param) (HGPIO_##param >> HGPIO_PORT_POS)
/*
*/
#define HGPIO_PIN_0   (0x0001 << HGPIO_PIN_POS)
#define HGPIO_PIN_1   (0x0002 << HGPIO_PIN_POS)
#define HGPIO_PIN_2   (0x0004 << HGPIO_PIN_POS)
#define HGPIO_PIN_3   (0x0008 << HGPIO_PIN_POS)
#define HGPIO_PIN_4   (0x0010 << HGPIO_PIN_POS)
#define HGPIO_PIN_5   (0x0020 << HGPIO_PIN_POS)
#define HGPIO_PIN_6   (0x0040 << HGPIO_PIN_POS)
#define HGPIO_PIN_7   (0x0080 << HGPIO_PIN_POS)
#define HGPIO_PIN_8   (0x0100 << HGPIO_PIN_POS)
#define HGPIO_PIN_9   (0x0200 << HGPIO_PIN_POS)
#define HGPIO_PIN_10  (0x0400 << HGPIO_PIN_POS)
#define HGPIO_PIN_11  (0x0800 << HGPIO_PIN_POS)
#define HGPIO_PIN_12  (0x1000 << HGPIO_PIN_POS)
#define HGPIO_PIN_13  (0x2000 << HGPIO_PIN_POS)
#define HGPIO_PIN_14  (0x4000 << HGPIO_PIN_POS)
#define HGPIO_PIN_15  (0x8000 << HGPIO_PIN_POS)
#define HGPIO_PIN(param) (HGPIO_PIN_##param >> HGPIO_PIN_POS)
/*
*/
#define HGPIO_MODE_IN     (0 << HGPIO_MODE_POS)  
#define HGPIO_MODE_OUT    (1 << HGPIO_MODE_POS)  
#define HGPIO_MODE_AF     (2 << HGPIO_MODE_POS)
#define HGPIO_MODE_AN     (3 << HGPIO_MODE_POS)
#define HGPIO_MODE_AF0   (4 << HGPIO_MODE_POS)
#define HGPIO_MODE_AF1   (5 << HGPIO_MODE_POS)
#define HGPIO_MODE_AF2   (6 << HGPIO_MODE_POS)
#define HGPIO_MODE_AF3   (7 << HGPIO_MODE_POS)
#define HGPIO_MODE_AF4   (8 << HGPIO_MODE_POS)
#define HGPIO_MODE_AF5   (9 << HGPIO_MODE_POS)
#define HGPIO_MODE_AF6   (10 << HGPIO_MODE_POS)
#define HGPIO_MODE_AF7   (11 << HGPIO_MODE_POS)
#define HGPIO_MODE_AF8   (12 << HGPIO_MODE_POS)
#define HGPIO_MODE_AF9   (13 << HGPIO_MODE_POS)
#define HGPIO_MODE_AF10  (14 << HGPIO_MODE_POS)
#define HGPIO_MODE_AF11  (15 << HGPIO_MODE_POS)
#define HGPIO_MODE_AF12  (16 << HGPIO_MODE_POS)
#define HGPIO_MODE_AF13  (17 << HGPIO_MODE_POS)
#define HGPIO_MODE_AF14  (18 << HGPIO_MODE_POS)
#define HGPIO_MODE_AF15  (19 << HGPIO_MODE_POS)
#define HGPIO_MODE(param) (HGPIO_MODE_##param >> HGPIO_MODE_POS)
/*
*/
#define HGPIO_TYPE_PP     (0 << HGPIO_TYPE_POS)
#define HGPIO_TYPE_OD     (1 << HGPIO_TYPE_POS)
#define HGPIO_TYPE_PU     (2 << HGPIO_TYPE_POS)
#define HGPIO_TYPE_PD     (3 << HGPIO_TYPE_POS)
#define HGPIO_TYPE_FT     (4 << HGPIO_TYPE_POS)
#define HGPIO_TYPE(param) (HGPIO_TYPE_##param >> HGPIO_TYPE_POS)
/*
*/
#define HGPIO_SPEED_SLOW    (0 << HGPIO_SPEED_POS)
#define HGPIO_SPEED_MEDIUM  (1 << HGPIO_SPEED_POS)
#define HGPIO_SPEED_HIGH    (2 << HGPIO_SPEED_POS)
#define HGPIO_SPEED_FAST    (3 << HGPIO_SPEED_POS)
#define HGPIO_SPEED(param) (HGPIO_SPEED_##param >> HGPIO_SPEED_POS)
/*
*/
#define HGPIO_STATUS_RESET  (0 << HGPIO_STATUS_POS)
#define HGPIO_STATUS_SET    (1 << HGPIO_STATUS_POS)
#define HGPIO_STATUS(param) (HGPIO_STATUS_##param >> HGPIO_STATUS_POS)
/*
*/
#define HGPIO_EXTI_NONE    (0ll << HGPIO_EXTI_POS)
#define HGPIO_EXTI_INTRT   (1ll << HGPIO_EXTI_POS)   //Interrupt, trigger rising
#define HGPIO_EXTI_INTFT   (2ll << HGPIO_EXTI_POS)   //Interrupt, trigger falling
#define HGPIO_EXTI_INTRFT  (3ll << HGPIO_EXTI_POS)   //Interrupt, trigger rising falling
#define HGPIO_EXTI_EVTRT   (4ll << HGPIO_EXTI_POS)   //Event, trigger rising
#define HGPIO_EXTI_EVTFT   (5ll << HGPIO_EXTI_POS)   //Event, trigger falling
#define HGPIO_EXTI_EVTRFT  (6ll << HGPIO_EXTI_POS)   //Event, trigger rising falling
#define HGPIO_EXTI(param)  (HGPIO_EXTI_##param >> HGPIO_EXTI_POS)
/*
*/
#define HGPIO_CFG_EXTRACT(cfg, name)  ((cfg >> HGPIO_##name##_POS) & HGPIO_##name##_MASK)

/*
*/
class HAL_GPIO
{
public:
  HAL_GPIO() :
    port(0),
    pin(0),
    cfg(0),
    _index(0)
  {}
    
  uint32_t port;
  uint32_t pin;
  uint64_t cfg;
  
  bool     init(uint64_t cfg0);
  bool     config(uint64_t cfg0);  //Just config the param with CFG_MASK
  void     remap(uint32_t remap);
  uint16_t read();
  void     write(uint16_t value);
  void     set() {write(pin);}
  void     reset() {write(~pin);}
  void     toggle();
  uint8_t  output_state();
  uint8_t  input_state();
  void     set_mode(uint64_t cfg0) {
              cfg &= ~(HGPIO_MODE_MASK << HGPIO_MODE_POS);
              cfg |= cfg0 & (HGPIO_MODE_MASK << HGPIO_MODE_POS);
              config(cfg);
           }
  void     attach_irq(void(*fun)(void *param), void *param);
  void     detach_irq() {
              attach_irq(nullptr, nullptr);
           }
    
private:
  uint8_t  _index;
};




